#include "Debug.h"
#include "Const.h"
#include "Utils.h"
#include "Mutex.h"
#include "utility/Instruction.h"

static MutexType mutex;


void SysPrintMsg(char* fmt, int arg)
{
    Log(fmt, arg);
}

void InitDebug()
{
    InitMutex(&mutex);
    // The question is why log info is available by using serial port?
    // Because when using QEMU, the serial port output is automatically redirected.

    // Reference: https://wiki.osdev.org/Serial_Ports
    Outb(COM1_PORT + 1, 0x00);    // Disable all interrupts
    Outb(COM1_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
    Outb(COM1_PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
    Outb(COM1_PORT + 1, 0x00);    //                  (hi byte)
    Outb(COM1_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
    Outb(COM1_PORT + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
  
    // If serial is not faulty set it in normal operation mode
    // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
    Outb(COM1_PORT + 4, 0x0F);
}

void Log(const char* string, ...)
{
    LockMutex(&mutex);
    char buffer[128];
    Memset(buffer, '\0', sizeof(buffer));
    va_list args;
    va_start(args, string);
    StringFormatArgs(buffer, string, args);
    va_end(args);

    // Because ports are public, it need to be protected when using
    // A temp way to show data on serial
    const char * p = buffer;    
    while (*p != '\0') {
        while ((Inb(COM1_PORT + 5) & (1 << 6)) == 0);
        Outb(COM1_PORT, *p++);
    }
    
    Outb(COM1_PORT, '\r');
    Outb(COM1_PORT, '\n');
    UnlockMutex(&mutex);
}